#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <gmp.h>
#include "gauss-legendre.h"

#define MAX_IT 40
#define IT_FILENAME "resultados/pth"
#define F_PREC 33219613

pthread_t callThd[4];
pthread_mutex_t pi_used_a, pi_used_b, pi_used_t;
pthread_mutex_t t_used_a, t_ready;
pthread_mutex_t a_ready2t, a_ready2pi;
pthread_mutex_t b_ready;

void *a_calc_thr(void* arg){
	while(1){
		pthread_mutex_lock(&t_used_a);
		pthread_mutex_lock(&pi_used_a);
		calc_new_a();
		pthread_mutex_unlock(&a_ready2t);
		pthread_mutex_unlock(&a_ready2pi);
	}
	pthread_exit(NULL);
}

void *b_calc_thr(void* arg){
	while(1){
		pthread_mutex_lock(&pi_used_b);
		calc_new_b();
		pthread_mutex_unlock(&b_ready);
	}
	pthread_exit(NULL);
}

void *t_calc_thr(void* arg){
	while(1){
		pthread_mutex_lock(&a_ready2t);
		t_use_a();
		pthread_mutex_unlock(&t_used_a);
		t_pre_calc();
		pthread_mutex_lock(&pi_used_t);
		set_new_t();
		pthread_mutex_unlock(&t_ready);
	}
	pthread_exit(NULL);
}

void *pi_calc_thr(void* arg){
	int it = 0;

	do{
		pthread_mutex_lock(&b_ready);
		pthread_mutex_lock(&a_ready2pi);
		pi_use_ab();
		pthread_mutex_unlock(&pi_used_b);
		pthread_mutex_unlock(&pi_used_a);
		pi_pre_calc();
		pthread_mutex_lock(&t_ready);
		pi_end_calc_use_t();
		pthread_mutex_unlock(&pi_used_t);
		save_it(IT_FILENAME);
	}while(check_erro() && MAX_IT > ++it);

	pthread_exit(NULL);	
}


int main (int argc, char** argv){
	unsigned int t;
	void * status;

	mpf_set_default_prec(F_PREC);       

	pthread_mutex_init(&pi_used_a, NULL);
	pthread_mutex_init(&pi_used_b, NULL);
	pthread_mutex_init(&pi_used_t, NULL);
	pthread_mutex_init(&t_used_a, NULL);
	pthread_mutex_init(&t_ready, NULL);
	pthread_mutex_init(&a_ready2t, NULL);
	pthread_mutex_init(&a_ready2pi, NULL);
	pthread_mutex_init(&t_ready, NULL);

	t = time(NULL);	

	init_vals();

	pthread_mutex_lock(&t_ready);
	pthread_mutex_lock(&a_ready2t);
	pthread_mutex_lock(&a_ready2pi);
	pthread_mutex_lock(&b_ready);

	pthread_create(&callThd[0], NULL, pi_calc_thr, NULL);
	pthread_create(&callThd[1], NULL, b_calc_thr, NULL);
	pthread_create(&callThd[2], NULL, a_calc_thr, NULL);
	pthread_create(&callThd[3], NULL, t_calc_thr, NULL);

	pthread_join(callThd[0], &status);
	pthread_cancel(callThd[1]);
	pthread_cancel(callThd[2]);
	pthread_cancel(callThd[3]);

	printf("Tempo total %d segundos.\n", (int) time(NULL)-t);

	return EXIT_SUCCESS;
}
